#include "tests.h"

TEST(ListTest, DefaultConstructor) {
  s21::list<int> list;

  EXPECT_TRUE(list.empty());
}

TEST(ListTest, SizeConstructor_ZeroSize) {
  s21::list<int> list(0);

  EXPECT_TRUE(list.empty());
}

TEST(ListTest, SizeConstructor_PositiveSize) {
  const size_t size = 5;
  s21::list<int> list(size);

  EXPECT_EQ(list.size(), size);
}

TEST(ListTest, InitializerListConstructor_EmptyList) {
  s21::list<int> list = {};

  EXPECT_TRUE(list.empty());
}

TEST(ListTest, InitializerListConstructor_NonEmptyList) {
  s21::list<int> list = {1, 2, 3, 4, 5, 6, 7, 8, 9};

  EXPECT_EQ(list.size(), 9);
  size_t i = 0;
  for (auto it = list.begin(); it != list.end(); ++it) {
    EXPECT_EQ(*it, ++i);
  }
}

TEST(ListTest, CopyConstructor_EmptyList) {
  s21::list<int> list;
  s21::list<int> copy(list);

  EXPECT_TRUE(list.empty());
  EXPECT_TRUE(copy.empty());
}

TEST(ListTest, CopyConstructor_NonEmptyList) {
  s21::list<int> list{1, 2, 3};
  s21::list<int> copy(list);

  EXPECT_EQ(list.size(), 3);
  EXPECT_EQ(list.front(), 1);
  EXPECT_EQ(list.back(), 3);
  EXPECT_EQ(copy.size(), 3);
  EXPECT_EQ(copy.front(), 1);
  EXPECT_EQ(copy.back(), 3);
}

TEST(ListTest, MoveConstructor_EmptyList) {
  s21::list<int> list;
  s21::list<int> dist(std::move(list));

  EXPECT_TRUE(list.empty());
  EXPECT_TRUE(dist.empty());
}

TEST(ListTest, MoveConstructor_NonEmptyList) {
  s21::list<int> list{1, 2, 3};
  s21::list<int> dist{std::move(list)};

  EXPECT_TRUE(list.empty());
  EXPECT_EQ(dist.size(), 3);
  EXPECT_EQ(dist.front(), 1);
  EXPECT_EQ(dist.back(), 3);
}

TEST(ListTest, CopyAssignmentOperator_NonEmptyToEmpty) {
  s21::list<int> list1 = {1, 2, 3};
  s21::list<int> list2;

  list2 = list1;

  EXPECT_EQ(list2.size(), list1.size());
  EXPECT_EQ(list2.front(), list1.front());
  EXPECT_EQ(list2.back(), list1.back());
}

TEST(ListTest, CopyAssignmentOperator_EmptyToNonEmpty) {
  s21::list<int> list1;
  s21::list<int> list2 = {4, 5, 6};

  list2 = list1;

  EXPECT_TRUE(list1.empty());
  EXPECT_TRUE(list2.empty());
}

TEST(ListTest, CopyAssignmentOperator_NonEmptyToNonEmpty) {
  s21::list<int> list1 = {1, 2, 3};
  s21::list<int> list2 = {4, 5, 6, 7, 8};

  list2 = list1;

  EXPECT_EQ(list2.size(), list1.size());
  EXPECT_EQ(list2.front(), list1.front());
  EXPECT_EQ(list2.back(), list1.back());
}

TEST(ListTest, MoveAssignmentOperator_NonEmptyToEmpty) {
  s21::list<int> list1 = {1, 2, 3};
  s21::list<int> list2;

  list2 = std::move(list1);

  EXPECT_EQ(list2.size(), 3);
  EXPECT_EQ(list2.front(), 1);
  EXPECT_EQ(list2.back(), 3);
  EXPECT_TRUE(list1.empty());
}

TEST(ListTest, MoveAssignmentOperator_EmptyToNonEmpty) {
  s21::list<int> list1;
  s21::list<int> list2 = {4, 5, 6};

  list2 = std::move(list1);

  EXPECT_TRUE(list1.empty());
  EXPECT_TRUE(list2.empty());
}

TEST(ListTest, MoveAssignmentOperator_NonEmptyToNonEmpty) {
  s21::list<int> list1 = {1, 2, 3};
  s21::list<int> list2 = {4, 5, 6, 7, 8};

  list2 = std::move(list1);

  EXPECT_EQ(list2.size(), 3);
  EXPECT_EQ(list2.front(), 1);
  EXPECT_EQ(list2.back(), 3);
  EXPECT_TRUE(list1.empty());
}

TEST(ListTest, Front) {
  s21::list<int> list{9, 2};

  EXPECT_EQ(list.front(), 9);
}

TEST(ListTest, Back) {
  s21::list<int> list{1, 2, 3, 4, 7};

  EXPECT_EQ(list.back(), 7);
}

TEST(ListTest, constFront) {
  const s21::list<int> list{4, 5};

  EXPECT_EQ(list.front(), 4);
}

TEST(ListTest, constBack) {
  const s21::list<int> list{6};

  EXPECT_EQ(list.back(), 6);
}

TEST(ListTest, Empty) {
  s21::list<int> list;

  EXPECT_TRUE(list.empty());

  list.push_back(1);

  EXPECT_FALSE(list.empty());
}

TEST(ListTest, Size_EmptyList) {
  s21::list<int> list;

  EXPECT_EQ(list.size(), 0);
}

TEST(ListTest, Size_NonEmptyList) {
  s21::list<int> list{1, 2, 3, 4, 5, 6, 7, 8};

  EXPECT_EQ(list.size(), 8);
}

TEST(ListTest, MaxSize) {
  s21::list<size_t> list;

  EXPECT_GT(list.max_size(), 0);
}

TEST(ListTest, Begin_End_EmptyList) {
  s21::list<int> list;

  EXPECT_EQ(list.begin(), list.end());
}

TEST(ListTest, Begin_ValidList) {
  s21::list<int> list = {1, 2, 3, 4, 5};

  auto it = list.begin();

  EXPECT_EQ(*it, 1);
}

TEST(ListTest, CBegin_CEnd_EmptyList) {
  const s21::list<int> list;

  EXPECT_EQ(list.cbegin(), list.cend());
}

TEST(ListTest, CBegin_ValidList) {
  const s21::list<int> list = {1, 2, 3, 4, 5};

  auto it = list.cbegin();

  EXPECT_EQ(*it, 1);
}

TEST(ListTest, Clear_EmptyList) {
  s21::list<int> list;

  list.clear();

  EXPECT_TRUE(list.empty());
}

TEST(ListTest, Clear_NonEmptyList) {
  s21::list<int> list{1, 2, 3, 4};

  list.clear();

  EXPECT_TRUE(list.empty());
}

TEST(ListTest, Insert_RV_Begin_EmptyList) {
  s21::list<int> list;
  auto it = list.begin();

  it = list.insert(it, 1);

  EXPECT_EQ(list.size(), 1);
  EXPECT_EQ(*it, 1);
  EXPECT_EQ(list.front(), 1);
  EXPECT_EQ(list.back(), 1);
}

TEST(ListTest, Insert_RV_Begin_NonEmptyList) {
  s21::list<int> list{2, 3, 4, 5};
  auto it = list.begin();

  it = list.insert(it, 1);

  EXPECT_EQ(list.size(), 5);
  EXPECT_EQ(*it, 1);
  size_t i = 0;
  for (auto it = list.begin(); it != list.end(); ++it) {
    EXPECT_EQ(*it, ++i);
  }
}

TEST(ListTest, Insert_RV_Mid) {
  s21::list<int> list{1, 2, 4, 5};
  auto it = list.end();
  it--;
  it--;

  it = list.insert(it, 3);

  EXPECT_EQ(list.size(), 5);
  EXPECT_EQ(*it, 3);
  size_t i = 0;
  for (auto it = list.begin(); it != list.end(); ++it) {
    EXPECT_EQ(*it, ++i);
  }
}

TEST(ListTest, Insert_RV_End) {
  s21::list<int> list{1, 2, 3, 4};
  auto it = list.end();

  it = list.insert(it, 5);

  EXPECT_EQ(list.size(), 5);
  EXPECT_EQ(*it, 5);
  size_t i = 0;
  for (auto it = list.begin(); it != list.end(); ++it) {
    EXPECT_EQ(*it, ++i);
  }
}

TEST(ListTest, Insert_LV) {
  s21::list<int> list{1, 2, 4, 5};
  const int number = 3;
  auto it = list.end();
  it--;
  it--;

  it = list.insert(it, number);

  EXPECT_EQ(list.size(), 5);
  EXPECT_EQ(*it, number);
  size_t i = 0;
  for (auto it = list.begin(); it != list.end(); ++it) {
    EXPECT_EQ(*it, ++i);
  }
}

TEST(ListTest, Erase_Fornt) {
  s21::list<int> list{1, 2, 3, 4, 5};
  auto it = list.begin();

  list.erase(it);

  EXPECT_EQ(list.size(), 4);
  EXPECT_EQ(list.front(), 2);
  EXPECT_EQ(list.back(), 5);
}

TEST(ListTest, Erase_Back) {
  s21::list<int> list{1, 2, 3, 4, 5};
  auto it = list.end();
  it--;

  list.erase(it);

  EXPECT_EQ(list.size(), 4);
  EXPECT_EQ(list.front(), 1);
  EXPECT_EQ(list.back(), 4);
}

TEST(ListTest, PushBack_RV) {
  s21::list<int> list{1, 2, 3, 4, 5};

  list.push_back(6);

  EXPECT_EQ(list.size(), 6);
  EXPECT_EQ(list.back(), 6);
}

TEST(ListTest, PushBack_LV) {
  s21::list<int> list{1, 2, 3, 4, 5};
  const int number = 6;

  list.push_back(number);

  EXPECT_EQ(list.size(), 6);
  EXPECT_EQ(list.back(), number);
}

TEST(ListTest, PopBack) {
  s21::list<int> list{1, 2, 3, 4, 5};

  list.pop_back();

  EXPECT_EQ(list.size(), 4);
  EXPECT_EQ(list.back(), 4);
}

TEST(ListTest, PushFront_RV) {
  s21::list<int> list{1, 2, 3, 4, 5};

  list.push_front(0);

  EXPECT_EQ(list.size(), 6);
  EXPECT_EQ(list.front(), 0);
}

TEST(ListTest, PushFront_LV) {
  s21::list<int> list{1, 2, 3, 4, 5};
  const int number = 0;

  list.push_front(number);

  EXPECT_EQ(list.size(), 6);
  EXPECT_EQ(list.front(), number);
}

TEST(ListTest, PopFront) {
  s21::list<int> list{1, 2, 3, 4, 5};

  list.pop_front();

  EXPECT_EQ(list.size(), 4);
  EXPECT_EQ(list.front(), 2);
}

TEST(ListTest, Swap_NonEmptyWithNonEmpty) {
  s21::list<int> list1{1, 2, 3, 4, 5};
  s21::list<int> list2{6, 7, 8, 9, 10, 11};

  list1.swap(list2);

  EXPECT_EQ(list1.size(), 6);
  EXPECT_EQ(list1.front(), 6);
  EXPECT_EQ(list1.back(), 11);
  EXPECT_EQ(list2.size(), 5);
  EXPECT_EQ(list2.front(), 1);
  EXPECT_EQ(list2.back(), 5);
}

TEST(ListTest, Swap_NonEmptyWithEmpty) {
  s21::list<int> list1{1, 2, 3};
  s21::list<int> list2;

  list1.swap(list2);

  EXPECT_TRUE(list1.empty());
  EXPECT_EQ(list2.size(), 3);
  EXPECT_EQ(list2.front(), 1);
  EXPECT_EQ(list2.back(), 3);
}

TEST(ListTest, Swap_EmptyWithEmpty) {
  s21::list<int> list1;
  s21::list<int> list2;

  list1.swap(list2);

  EXPECT_TRUE(list1.empty());
  EXPECT_TRUE(list2.empty());
}

TEST(ListTest, Merge_NonEmptyWithNonEmpty_1) {
  s21::list<int> list1{2, 3, 6, 7, 8, 9};
  s21::list<int> list2{1, 4, 5};

  list1.merge(list2);

  EXPECT_EQ(list1.size(), 9);
  size_t i = 0;
  for (auto it = list1.begin(); it != list1.end(); ++it) {
    EXPECT_EQ(*it, ++i);
  }
  EXPECT_TRUE(list2.empty());
}

TEST(ListTest, Merge_NonEmptyWithNonEmpty_2) {
  s21::list<int> list1{4, 5, 6, 9};
  s21::list<int> list2{1, 2, 3, 7, 8};

  list1.merge(list2);

  EXPECT_EQ(list1.size(), 9);
  size_t i = 0;
  for (auto it = list1.begin(); it != list1.end(); ++it) {
    EXPECT_EQ(*it, ++i);
  }
  EXPECT_TRUE(list2.empty());
}

TEST(ListTest, Merge_NonEmptyWithNonEmpty_3) {
  s21::list<int> list1{1, 3, 5, 7};
  s21::list<int> list2{2, 4, 6, 8, 9};

  list1.merge(list2);

  EXPECT_EQ(list1.size(), 9);
  size_t i = 0;
  for (auto it = list1.begin(); it != list1.end(); ++it) {
    EXPECT_EQ(*it, ++i);
  }
  EXPECT_TRUE(list2.empty());
}

TEST(ListTest, Merge_EmptyWithNonEmpty) {
  s21::list<int> list1;
  s21::list<int> list2{1, 2, 3, 4, 5, 6, 7, 8, 9};

  list1.merge(list2);

  EXPECT_EQ(list1.size(), 9);
  size_t i = 0;
  for (auto it = list1.begin(); it != list1.end(); ++it) {
    EXPECT_EQ(*it, ++i);
  }
  EXPECT_TRUE(list2.empty());
}

TEST(ListTest, Merge_NonEmptyWithEmpty) {
  s21::list<int> list1{1, 2, 3, 4, 5, 6, 7, 8, 9};
  s21::list<int> list2;

  list1.merge(list2);

  EXPECT_EQ(list1.size(), 9);
  size_t i = 0;
  for (auto it = list1.begin(); it != list1.end(); ++it) {
    EXPECT_EQ(*it, ++i);
  }
  EXPECT_TRUE(list2.empty());
}

TEST(ListTest, Splice) {
  s21::list<int> list1{5, 6, 7, 8, 9};
  s21::list<int> list2{1, 2, 3, 4};
  auto it = list1.cbegin();

  list1.splice(it, list2);

  EXPECT_EQ(list1.size(), 9);
  size_t i = 0;
  for (auto it = list1.begin(); it != list1.end(); ++it) {
    EXPECT_EQ(*it, ++i);
  }
  EXPECT_TRUE(list2.empty());
}

TEST(ListTest, Reverse_NonEmpty) {
  s21::list<int> list{1, 2, 3, 4, 5};

  list.reverse();

  EXPECT_EQ(list.size(), 5);
  size_t i = 6;
  for (auto it = list.begin(); it != list.end(); ++it) {
    EXPECT_EQ(*it, --i);
  }
}

TEST(ListTest, Reverse_Empty) {
  s21::list<int> list;

  list.reverse();

  EXPECT_TRUE(list.empty());
}

TEST(ListTest, Unique_1) {
  s21::list<int> list{1, 1, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 9};

  list.unique();

  EXPECT_EQ(list.size(), 9);
  size_t i = 0;
  for (auto it = list.begin(); it != list.end(); ++it) {
    EXPECT_EQ(*it, ++i);
  }
}

TEST(ListTest, Unique_2) {
  s21::list<int> list{1, 1, 1, 2, 1, 1, 2, 2, 2, 1};

  list.unique();
  auto it = list.begin();

  EXPECT_EQ(list.size(), 5);
  EXPECT_EQ(*it, 1);
  it++;
  EXPECT_EQ(*it, 2);
  it++;
  EXPECT_EQ(*it, 1);
  it++;
  EXPECT_EQ(*it, 2);
  it++;
  EXPECT_EQ(*it, 1);
}

TEST(ListTest, Sort_1) {
  s21::list<int> list{4, 7, 6, 2, 1, 9, 3, 8, 5};

  list.sort();

  EXPECT_EQ(list.size(), 9);
  size_t i = 0;
  for (auto it = list.begin(); it != list.end(); ++it) {
    EXPECT_EQ(*it, ++i);
  }
}

TEST(ListTest, Sort_2) {
  s21::list<int> list{9, 7, 5, 3, 1, 2, 4, 6, 8};

  list.sort();

  EXPECT_EQ(list.size(), 9);
  size_t i = 0;
  for (auto it = list.begin(); it != list.end(); ++it) {
    EXPECT_EQ(*it, ++i);
  }
}

TEST(ListTest, Sort_3) {
  s21::list<int> list{3, 2, 8, 4, 7, 6, 9, 5, 1};

  list.sort();

  EXPECT_EQ(list.size(), 9);
  size_t i = 0;
  for (auto it = list.begin(); it != list.end(); ++it) {
    EXPECT_EQ(*it, ++i);
  }
}

TEST(ListTest, Insert_Many) {
  s21::list<int> list = {1, 2, 3, 7, 8};
  auto cit = list.cbegin();
  cit++;
  cit++;
  cit++;

  list.insert_many(cit, 4, 5, 6);

  EXPECT_EQ(list.size(), 8);
  size_t i = 0;
  for (auto it = list.begin(); it != list.end(); ++it) {
    EXPECT_EQ(*it, ++i);
  }
}

TEST(ListTest, Insert_Many_Back) {
  s21::list<int> list;

  list.insert_many_back(1, 2, 3, 4);

  EXPECT_EQ(list.size(), 4);
  size_t i = 0;
  for (auto it = list.begin(); it != list.end(); ++it) {
    EXPECT_EQ(*it, ++i);
  }
}

TEST(ListTest, Insert_Many_Front) {
  s21::list<int> list = {4, 5, 6};

  list.insert_many_front(1, 2, 3);

  EXPECT_EQ(list.size(), 6);
  size_t i = 0;
  for (auto it = list.begin(); it != list.end(); ++it) {
    EXPECT_EQ(*it, ++i);
  }
}